import { Point, Range, NodeType } from '../../reducer/const';

interface IModel {
    history?: boolean; // 是否是历史节点
}

class Model implements IModel {
    history?: boolean; // 是否是历史节点
}

export interface INode extends IModel {
    id: string;
    type: number;
    name: string;
    icon: string;
    range: Range;
}

export class NodeModel extends Model implements INode {

    id: string;
    type: number;
    name: string;
    icon: string;
    range: Range = new Range();
    fromLines: LineModel[] = new Array<LineModel>();
    toLines: LineModel[] = new Array<LineModel>();

    public parse(json: any, offset: Point = { x: 0, y: 0 }) {
        this.id = json.id;
        this.type = json.type;
        this.name = json.name;
        this.icon = json.icon;
        this.history = json.history;
        const {x, y, r} = json.range || json;
        this.initRange(x + offset.x, y + offset.y, r);
    }

    public initRange = (x: number = 0, y: number = 0, r: number = 8) => {
        this.range.r = r;
        switch (this.type) {
            case NodeType.StartNode: ;
            case NodeType.CompleteNode: ;
            case NodeType.EndNode: ;
            case NodeType.ErrorNode:
                this.range.width = 40;
                this.range.height = 40;
                this.range.r = 30;
                break;
            case NodeType.BranchNode: ;
            case NodeType.MegerNode: ;
            case NodeType.ConditionNode:
            case NodeType.SyncNode:
                this.range.width = 40;
                this.range.height = 40;
                this.range.r = 0;
                break;
            default:
                this.range.width = 140;
                this.range.height = 40;
                break;
        }

        this.range.x = x - this.range.width / 2;
        this.range.y = y - this.range.height / 2;
    }

    public resetPosition = (x: number, y: number) => {
        this.range.x = x;
        this.range.y = y;
    }

    public getProps = () => {
        const props: INode = {
            id: this.id,
            type: this.type,
            name: this.name,
            icon: this.icon,
            history: this.history,
            range: this.range,
        };
        return props;
    }

    public toString = (): string => {
        const json: string[] = [];
        json.push('{}');
        json.push(`'id':'${this.id}',`);
        json.push(`'type':'${this.type}',`);
        json.push(`'name':'${this.name}',`);
        json.push(`'icon':'${this.icon}',`);
        json.push(`'range':${this.rangeToJson()},`);
        json.push(`'fromLines':[${this.lineToJson(this.fromLines)}],`);
        json.push(`'toLines':[${this.lineToJson(this.toLines)}],`);
        json.push('}');
        return json.join('');
    }

    private rangeToJson = (): string => {
        const json: string[] = [];
        json.push('{');
        json.push(`'x':'${this.range.x}',`);
        json.push(`'y':'${this.range.y}',`);
        json.push(`'width':'${this.range.width}',`);
        json.push(`'height':'${this.range.height}',`);
        json.push(`'r':'${this.range.r}',`);
        json.push('}');
        return json.join('');
    }

    private lineToJson = (lines: LineModel[]): string => {
        const json: string[] = [];
        json.push('[');
        lines.map((item) => {
            json.push(`'${item.id}'`);
        });
        return json.join(',');
    }
}

// ?
export interface ILine extends IModel {
    id: string;
    type: number;
    from: NodeModel;
    to: NodeModel;
}

export class LineModel extends Model implements ILine {
    id: string;
    type: number;
    from: NodeModel;
    to: NodeModel;
    fromId: string;
    toId: string;

    public parse(json: any, offset: Point = { x: 0, y: 0 }) {
        this.id = json.id;
        this.type = json.type;
        this.history = json.history;
        this.autoId();
    }

    public getProps = () => {
        const props: ILine = {
            id: this.id,
            type: this.type,
            history: this.history,
            from: this.from,
            to: this.to,
        };
        return props;
    }

    public autoId = () => {
        if (!this.from || !this.to) {
            return console.log('please set from and to Node before call autoId');
        }
        this.id = `${this.from.id}->${this.to.id}`;
    }

    public toString = (): string => {
        const json: string[] = [];
        json.push('{}');
        json.push(`'id':'${this.id}',`);
        json.push(`'type':'${this.type}',`);
        json.push(`'from':'${this.from && this.from.id}',`);
        json.push(`'to':'${this.to && this.to.id}',`);
        json.push('}');
        return json.join('');
    }
}
